package cn.ac.zing.server.hj212.stater;

import cn.ac.zing.server.hj212.context.ChannelContextHolder;
import cn.ac.zing.server.hj212.handler.ProtocolTypeHandler;
import cn.ac.zing.server.hj212.handler.ProtocolTypeHandlerFactory;
import cn.ac.zing.server.util.DateUtil;
import cn.ac.zing.server.util.SpringUtil;
import com.alibaba.fastjson.JSONObject;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import org.apache.commons.lang3.StringUtils;

import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

/**
 * 这个是212的Netty
 */
public class NettyStarter extends AbstractStarter {
    public NettyStarter(JSONObject config) {
        super(config);
    }

    @Override
    public void execute(JSONObject data) {
        // netty启动端口
        int port = data.getInteger("port");

        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 1024)
                    .childHandler(new ChannelInitializer<Channel>() {
                        @Override
                        protected void initChannel(Channel ch) throws Exception {
                            ByteBuf delimiter = Unpooled.copiedBuffer("\r\n".getBytes());
                            ch.pipeline()
                                    .addLast("http-aggregator", new HttpObjectAggregator(10000))
                                    .addLast("server-logging-handler", new LoggingHandler(LogLevel.DEBUG))
                                    .addLast("line-decoder", new DelimiterBasedFrameDecoder(1024, delimiter))
                                    .addLast("string-encoder", new StringEncoder(StandardCharsets.UTF_8))
                                    .addLast("string-decoder", new StringDecoder(StandardCharsets.UTF_8))
                                    .addLast(new ChannelInboundHandlerAdapter() {
                                        @Override
                                        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

                                            log.info("收到消息: {}", msg.toString());

                                            String message = "";
                                            if (msg instanceof ByteBuf) {
                                                message += ((ByteBuf) msg).toString(StandardCharsets.UTF_8);
                                            } else if (msg instanceof String) {
                                                message = (String) msg;
                                            } else {
                                                message = String.valueOf(msg);
                                            }
                                            // 处理接收的数据
                                            execMsg(ctx, message);
                                        }

                                        @Override
                                        public void channelActive(ChannelHandlerContext ctx) throws Exception {

                                            log.info("channel [{}] 接入", ctx.channel().id().toString());
                                        }

                                        @Override
                                        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
                                            String mn = ChannelContextHolder.getMN(ctx);
                                            if (StringUtils.isBlank(mn)) {
                                                log.warn("未绑定 MN, Channel [{}] 断开", ctx.channel().id().toString());
                                            } else {
                                                ChannelContextHolder.removeChannelHandlerContext(ctx);
                                                log.info("Channel [{}] 断开", mn);
                                            }
                                        }

                                        @Override
                                        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
                                            super.userEventTriggered(ctx, evt);
                                        }

                                        @Override
                                        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                                            log.error("Channel [{}] 异常", ChannelContextHolder.getMN(ctx));
                                        }
                                    });
                        }
                    });
            log.info("netty启动, 端口: {}", port);
            ChannelFuture f = b.bind(port).sync();
            f.channel().closeFuture().sync();
        } catch (Exception e) {
            log.error("链接异常：===" + e.getMessage());
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    private void execMsg(ChannelHandlerContext ctx, String message) {

        JSONObject data = new JSONObject();

        InetSocketAddress inetSocket = (InetSocketAddress) ctx.channel().remoteAddress();

        data.put("ip", inetSocket.getAddress().getHostAddress());
        data.put("port", inetSocket.getPort());
        data.put("receiveTime", DateUtil.getCurrentMilliTime());

        // 这是接收到数据的处理
        JSONObject nodedata = new JSONObject();
        nodedata.put("ctx", ctx);
        nodedata.put("message", message);
        data.put("nodedata", nodedata);
        // 这是212协议
        if (message.startsWith("##")) {
            data.put("protocol", "212-2017");
            super.dispatch(data);
        } else { // 这里可以集成其他协议, 比如自定义的心跳协议 或者设备升级协议等等, 假设都是json类型的, 使用工厂+策略模式实现
            // 比如心跳协议 {"mn":"LP12456", "type":2 }
            JSONObject dta = JSONObject.parseObject(message);
            Integer type = dta.getInteger("type");
            ProtocolTypeHandlerFactory protocolTypeHandlerFactory = SpringUtil.getBean(ProtocolTypeHandlerFactory.class);
            ProtocolTypeHandler handler = protocolTypeHandlerFactory.getHandler(type);
            handler.execute(data);
        }
    }
}
